﻿using System;
using System.Collections.Generic;

using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;

namespace ISolutions.WCMTools.Impl
{
    /// <summary>
    /// This event handler, bound to a page library, will stop the variation propagation 
    /// process to overwrite pages with the version of the default language.
    /// 
    /// The event handler stores the language of the page on a hidden site column. When an update 
    /// is submitted checks the language field and if it comes from the variation progragation,
    /// the handler cancel the update.
    /// </summary>
    public class PageVariationReceiver : SPItemEventReceiver
    {
        public const string CT_SYSTEM_PAGE = "0x010100C568DB52D9D0A14D9B2FDCC96666E9F2";
        public const string CT_PAGE = "0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39";
        public const string FLD_VARIATIONLABEL = "VariationLabel";
        public const int USERID_SYSTEMACCOUNT = 1073741823;

        /// <summary>
        /// ItemAdding: Set the site language to the page.
        /// </summary>
        /// <param name="properties"></param>
        public override void ItemAdding(SPItemEventProperties properties)
        {
            using (SPWeb web = properties.OpenWeb())
            {
                if (PublishingWeb.IsPublishingWeb(web))
                {
                    PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
                    if (publishingWeb.Label != null)
                    {
                        string siteLabel = publishingWeb.Label.Title;
                        properties.AfterProperties[FLD_VARIATIONLABEL] = siteLabel;
                    }
                    publishingWeb.Close();
                }
            }
        }

        /// <summary>
        /// Checks the language of the site with the one of the item and cancels the
        /// update if necessary.
        /// </summary>
        /// <param name="properties"></param>
        public override void ItemUpdating(SPItemEventProperties properties)
        {
            using (SPWeb web = properties.OpenWeb())
            {
                if (PublishingWeb.IsPublishingWeb(web))
                {
                    PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
                    if (publishingWeb.Label != null)
                    {
                        string pageLabel = string.Empty;
                        try
                        {
                            pageLabel = (string)properties.AfterProperties[FLD_VARIATIONLABEL];
                        }
                        catch (Exception) { }

                        string siteLabel = publishingWeb.Label.Title;
                        if (string.IsNullOrEmpty(pageLabel))
                        {
                            properties.AfterProperties[FLD_VARIATIONLABEL] = siteLabel;
                        }
                        else if (!pageLabel.Equals(siteLabel, StringComparison.CurrentCultureIgnoreCase))
                        {
                            // HACK: When creating a new page, the initial value is not set corret. For this reason, we
                            // check if the 'system account' is updating the page.
                            if (properties.CurrentUserId == USERID_SYSTEMACCOUNT)
                            {
                                properties.Cancel = true;
                                properties.ErrorMessage = "Variation update not allowed";
                            }
                            else
                            {
                                properties.AfterProperties[FLD_VARIATIONLABEL] = siteLabel;
                            }
                        }
                    }
                    publishingWeb.Close();
                }
            }
        }

        /// <summary>
        /// Checks if the site column exists.
        /// 
        /// If the site column doesn't exist, then it is created
        /// </summary>
        /// <param name="pSite"></param>
        private static void CheckContentType(SPSite pSite)
        {
            SPContentTypeId ctId = new SPContentTypeId(CT_PAGE);
            SPContentType ct = pSite.RootWeb.ContentTypes[ctId];

            if (!ct.Fields.ContainsField(FLD_VARIATIONLABEL))
            {
                if (!pSite.RootWeb.Fields.ContainsField(FLD_VARIATIONLABEL))
                {
                    pSite.RootWeb.Fields.Add(FLD_VARIATIONLABEL, SPFieldType.Text, false);
                }
                SPField field = pSite.RootWeb.AvailableFields[FLD_VARIATIONLABEL];
                SPFieldLink link = new SPFieldLink(field);
                ct.FieldLinks.Add(link);
                //ct.Fields[FLD_VARIATIONLABEL].Hidden = true;
                ct.Update(true);
                ct.Fields[FLD_VARIATIONLABEL].Hidden = true;
                ct.Update(true);
            }
        }

        /// <summary>
        /// Removes the event handler from Pages library
        /// </summary>
        /// <param name="pWeb"></param>
        public static void UnregisterEventHandler(SPWeb pWeb)
        {
            string className = typeof(PageVariationReceiver).FullName;
            string assemblyName = typeof(PageVariationReceiver).Assembly.ToString();

            if (PublishingWeb.IsPublishingWeb(pWeb))
            {
                PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(pWeb);
                if (publishingWeb.Label != null)
                {
                    SPList list = publishingWeb.PagesList;
                    for (int i = list.EventReceivers.Count - 1; i >= 0; i--)
                    {
                        SPEventReceiverDefinition erd = list.EventReceivers[i];
                        if (erd.Class.Equals(className))
                        {
                            erd.Delete();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Register the event handler from the Pages library 
        /// </summary>
        /// <param name="pWeb"></param>
        public static void RegisterEventHandler(SPWeb pWeb)
        {
            CheckContentType(pWeb.Site);

            int cnt = 0;
            string className = typeof(PageVariationReceiver).FullName;
            string assemblyName = typeof(PageVariationReceiver).Assembly.ToString();
            if (PublishingWeb.IsPublishingWeb(pWeb))
            {
                PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(pWeb);
                
                if (publishingWeb.Label != null)
                {
                        SPList list = publishingWeb.PagesList;
                        
                                for (int i = list.EventReceivers.Count - 1; i >= 0; i--)
                                {
                                    SPEventReceiverDefinition erd = list.EventReceivers[i];
                                    if (erd.Class.Equals(className))
                                    {
                                        erd.Delete();
                                    }
                                }

                                list.EventReceivers.Add(SPEventReceiverType.ItemAdding, assemblyName, className);
                                if (!publishingWeb.Label.IsSource)
                                {
                                    list.EventReceivers.Add(SPEventReceiverType.ItemUpdating, assemblyName, className);
                                }
                                list.Update();
                                cnt++;
                }
                publishingWeb.Close();
            }
        }
    }
}
